﻿using System;
using System.Collections.Generic;
using Newtonsoft.Json;
using BCCommon;
using BCCommon.Enums;
using BCService.Utils;
using BCDto.TMS.AgentWallet;
using BCEntity.TMS.AgentWallet;
using BCData.TMS.AgentWallet;
using BCCommon.PaymentEnums;
using BCDto.Sim.Admin.Admin;
using BCData.TMS.AgentFlowRecord;
using BCEntity.TMS.AgentFlowRecord;
using BCDto.TMS.AgentFlowRecord;
using BCEntity.Common.EntityNameConst;
using BCCommon.Extensions;

namespace BCService.TMS.AgentWallet
{
    public class AgentWalletService : IAgentWalletService
    {
        private readonly IAgentWalletData agentWalletData;
        private readonly IAgentFlowRecordData agentFlowRecordData;
        private readonly IDatabaseContext databaseContext;
        private readonly IRedisService redisService;
        private readonly string key = $"{EntityNameConst.AgentWalletEntity}";
        private readonly string keyFlowRecord = $"{EntityNameConst.AgentFlowRecordEntity}";

        public AgentWalletService(IAgentWalletData agentWalletData,
            IAgentFlowRecordData agentFlowRecordData,
            IDatabaseContext databaseContext,
            IRedisService redisService)
        {
            this.agentWalletData = agentWalletData;
            this.agentFlowRecordData = agentFlowRecordData;
            this.databaseContext = databaseContext;
            this.redisService = redisService;
        }

        public int ChangeAliPayAuthInfo(long userId, string payAuthInfo)
        {
            var result = agentWalletData.ChangeAliPayAuthInfo(userId, payAuthInfo);
            this.redisService.DeleteMultipleKey(key, false);
            return result;
        }

        public int ChangeWxPayAuthInfo(long userId, string payAuthInfo)
        {
            var result = agentWalletData.ChangeWxPayAuthInfo(userId, payAuthInfo);
            this.redisService.DeleteMultipleKey(key, false);
            return result;
        }

        public AgentWalletDto GetWalletByAgentId(long agentRecordId, bool showPassword = false)
        {
            string cacheKey = this.redisService.GetKey(key, agentRecordId);
            var resultRedis = this.redisService.TryGet(cacheKey, () =>
            {
                AgentWalletEntity entity = agentWalletData.GetWalletByAgentRecordId(agentRecordId);

                if (entity != null)
                {
                    AgentWalletDto Dto = entity.As<AgentWalletDto>();
                    //是否设置过支付密码
                    Dto.HasPayPwd = !string.IsNullOrWhiteSpace(entity.PayPassword);
                    //支付宝授权信息
                    Dto.AlipayAuthInfo = string.IsNullOrWhiteSpace(entity.AlipayAuthInfo) ? null : JsonConvert.DeserializeObject(entity.AlipayAuthInfo);
                    //微信支付授权信息
                    Dto.WxPayAuthInfo = string.IsNullOrWhiteSpace(entity.WxPayAuthInfo) ? null : JsonConvert.DeserializeObject(entity.WxPayAuthInfo);
                    if (!showPassword)
                    {
                        Dto.PayPassword = null;
                    }
                    return Dto;
                }
                else
                {
                    //钱包不存在创建
                    var newEntity = new AgentWalletEntity { AgentRecordId = agentRecordId, Balance = 0M };
                    entity = agentWalletData.Add(newEntity);
                }
                var dto = entity.As<AgentWalletDto>();
                dto.HasPayPwd = !string.IsNullOrWhiteSpace(entity.PayPassword);
                dto.AlipayAuthInfo = string.IsNullOrWhiteSpace(entity.AlipayAuthInfo) ? null : JsonConvert.DeserializeObject(entity.AlipayAuthInfo);
                dto.WxPayAuthInfo = string.IsNullOrWhiteSpace(entity.WxPayAuthInfo) ? null : JsonConvert.DeserializeObject(entity.WxPayAuthInfo);
                return dto;
            }, TimeSpan.FromDays(1));
            return resultRedis;


        }

        public PageableList<AgentFlowRecordDto> GetCurrentDriverWalletDetails(long? agentRecordId, string orderNo, FlowType? flowType,
            FlowDirectionType? flowDirection, PaymentChannelType? payChannel, DateTime? start, DateTime? end, bool? ascending, int pageIndex, int pageSize)
        {
            string cacheKey = this.redisService.GetKey(keyFlowRecord, agentRecordId, orderNo, flowType, flowDirection, payChannel, start,
                    end, ascending, pageIndex, pageSize);
            var resultRedis = this.redisService.TryGet(cacheKey, () =>
            {
                var (list, count) = this.agentFlowRecordData.GetPageableList(agentRecordId, orderNo, flowType, flowDirection, payChannel, start,
                    end, ascending, pageIndex, pageSize).GetAwaiter().GetResult();
                return new PageableList<AgentFlowRecordDto>
                {
                    Count = count,
                    Items = list.As<IEnumerable<AgentFlowRecordDto>>()
                };
            }, TimeSpan.FromDays(1));
            return resultRedis;
        }


        ///// <summary>
        ///// 查看指定用户的账单明细
        ///// </summary>
        ///// <param name="userId">用户编号</param>
        ///// <param name="ascending">升序排序</param>
        ///// <param name="pageIndex">分页页码</param>
        ///// <param name="pageSize">分页页数</param>
        ///// <returns></returns>
        //public PageableList<UserFlowRecordDto> GetFlowDetails(long? userId, bool? ascending, int pageIndex, int pageSize)
        //{
        //    var (list, count) = this.flowRecordData.GetFlowDetails(userId, ascending, pageIndex, pageSize).GetAwaiter().GetResult();
        //    return new PageableList<UserFlowRecordDto>
        //    {
        //        Count = count,
        //        Items = list.As<IEnumerable<UserFlowRecordDto>>()
        //    };
        //}

        public AgentWalletDto ResetPayPassword(string phone, long agentRecordId, AgentWalletResetRequestDto requestDto)
        {
            AgentWalletEntity entity = this.agentWalletData.GetWalletByAgentRecordId(agentRecordId);
            if (entity == null)
            {
                return null;
            }
            if (requestDto.OperatingType == ResetOperatingType.Modify)
            {
                if (requestDto.SourcePassword.SHA256(phone) != entity.PayPassword)
                {
                    throw new ArgumentException("旧密码错误");
                }
            }
            var dto = this.agentWalletData.ResetPayPassword(agentRecordId, requestDto.PayPassword.SHA256(phone)).As<AgentWalletDto>();
            //是否设置过支付密码
            dto.HasPayPwd = true;
            //支付宝授权信息
            dto.AlipayAuthInfo = string.IsNullOrWhiteSpace(entity.AlipayAuthInfo) ? null : JsonConvert.DeserializeObject(entity.AlipayAuthInfo);
            //微信支付授权信息
            dto.WxPayAuthInfo = string.IsNullOrWhiteSpace(entity.WxPayAuthInfo) ? null : JsonConvert.DeserializeObject(entity.WxPayAuthInfo);
            this.redisService.DeleteMultipleKey(key, false);
            return dto;
        }

        public AgentWalletDto ChangePayPassword(AdminDto admin, AgentWalletResetRequestDto requestDto)
        {
            AgentWalletEntity entity = this.agentWalletData.GetWalletByAgentRecordId(admin.AgentRecord.AgentRecordId);
            if (entity == null)
            {
                return null;
            }

            if (requestDto.SourcePassword.SHA256(admin.Phone) != entity.PayPassword)
            {
                throw new ArgumentException("支付密码错误。");
            }
            var dto = this.agentWalletData.ResetPayPassword(admin.AgentRecord.AgentRecordId, requestDto.PayPassword.SHA256(admin.Phone)).As<AgentWalletDto>();
            //是否设置过支付密码
            dto.HasPayPwd = true;
            //支付宝授权信息
            dto.AlipayAuthInfo = string.IsNullOrWhiteSpace(entity.AlipayAuthInfo) ? null : JsonConvert.DeserializeObject(entity.AlipayAuthInfo);
            //微信支付授权信息
            dto.WxPayAuthInfo = string.IsNullOrWhiteSpace(entity.WxPayAuthInfo) ? null : JsonConvert.DeserializeObject(entity.WxPayAuthInfo);
            this.redisService.DeleteMultipleKey(key, false);
            return dto;
        }

        public AgentWalletDto BalanceRecharge(AdminDto admin, decimal rechargeAmount, string rechargeNo, PaymentChannelType channelType)
        {
            AgentWalletDto wallet = GetWalletByAgentId(admin.AgentRecord.AgentRecordId);
            if (wallet != null)
            {
                var result = agentWalletData.BalanceRecharge(admin.AgentRecord.AgentRecordId, rechargeAmount + wallet.Balance);
                if (result == null)
                {
                    return null;
                }
                //增加余额充值流水
                AgentFlowRecordEntity agentFlowRecordEntity = new AgentFlowRecordEntity
                {
                    Amount = rechargeAmount,
                    OrderNo = rechargeNo,
                    CreateTime = DateTime.Now,
                    Balance = result.Balance,
                    Remark = $"代理商充值{rechargeAmount}元",
                    FlowDirection = FlowDirectionType.Income.ToString(),
                    FlowType = FlowType.AgentRecharge.ToString(),
                    FlowTypeName = FlowType.AgentRecharge.GetDescriptionString(),
                    Channel = channelType.ToString(),
                    AgentRecordId = admin.AgentRecord.AgentRecordId,
                    AgentName = admin.CompanyName,
                    RiskLevel = Compare.GetRiskLevel(rechargeAmount).ToString(),
                };
                agentFlowRecordData.InsertAsync(agentFlowRecordEntity);
                //TODO 添加系统流水记录
                //this.systemFinanceFlowRecordService.WriteSystemFinanceFlowRecord(current.UserId, rechargeAmount, rechargeNo, SystemFinanceFlowDirectionType.Income, FlowType.Recharge, channelType);
                return wallet;
            }
            this.redisService.DeleteMultipleKey(key, false);
            this.redisService.DeleteMultipleKey(keyFlowRecord, false);
            return null;
        }

        public AgentWalletDto UpdatePasswordErrorCount(AdminDto admin, int passwordErrorCount)
        {
            AgentWalletDto wallet = GetWalletByAgentId(admin.AgentRecord.AgentRecordId);
            if (wallet == null)
            {
                throw new ArgumentException("用户钱包不存在");
            }
            var result = this.agentWalletData.UpdatePasswordErrorCount(admin.AgentRecord.AgentRecordId, passwordErrorCount).GetAwaiter().GetResult();
            this.redisService.DeleteMultipleKey(key, false);
            return result.As<AgentWalletDto>();
        }

        public void ClearErrorCount()
        {
            this.agentWalletData.ClearErrorCount();
            this.redisService.DeleteMultipleKey(key, false);
        }

        public AgentWalletDto Update(AgentWalletDto walletDto)
        {
            AgentWalletEntity agentWalletEntity = this.agentWalletData.Get(walletDto.AgentWalletId);
            if (agentWalletEntity == null)
            {
                throw new ArgumentException("用户钱包不存在");
            }
            if (agentWalletEntity.AgentRecordId != walletDto.AgentRecordId)
            {
                throw new ArgumentException("请勿操作他人钱包");
            }
            agentWalletEntity.Balance = walletDto.Balance;
            var entity = this.agentWalletData.Update(agentWalletEntity);
            this.redisService.DeleteMultipleKey(key, false);
            return entity.As<AgentWalletDto>();
        }

        public AgentWalletDto FirstSetPayPassword(AdminDto admin, AgentWalletRequestDto requestDto)
        {
            var walletEntity = this.agentWalletData.GetWalletByAgentRecordId(admin.AgentRecord.AgentRecordId);
            if (requestDto.AgentWalletId != walletEntity.AgentWalletId)
            {
                throw new ArgumentException("钱包信息不正确");
            }
            if (!string.IsNullOrWhiteSpace(walletEntity.PayPassword))
            {
                throw new ArgumentException("已设置支付密码,无需重复设置");
            }
            walletEntity = this.agentWalletData.ResetPayPassword(admin.AgentRecord.AgentRecordId, requestDto.PayPassword.SHA256(admin.Phone));
            walletEntity.PayPassword = string.Empty;
            this.redisService.DeleteMultipleKey(key, false);
            return walletEntity.As<AgentWalletDto>();
        }


        public PageableList<AgentFlowRecordDto> AgentFlowRecord(long agentRecordId, FlowType? flowType, FlowDirectionType? flowDirectionType, decimal? minAmount,
            decimal? maxAmount, PaymentChannelType? paymentChannelType, DateTime? startDate, DateTime? endDate,
            bool? ascending, int pageIndex, int pageSize)
        {
            string cacheKey = this.redisService.GetKey(key, agentRecordId, flowType, flowDirectionType, minAmount, maxAmount, paymentChannelType, startDate, endDate, ascending, pageIndex,
                    pageSize);
            var resultRedis = this.redisService.TryGet(cacheKey, () =>
            {
                var (list, count) = this.agentFlowRecordData.GetAgentFlowDetails(agentRecordId, flowType, flowDirectionType, minAmount, maxAmount, paymentChannelType, startDate, endDate, ascending, pageIndex,
                    pageSize).GetAwaiter().GetResult();

                return new PageableList<AgentFlowRecordDto>
                {
                    Count = count,
                    Items = list.As<IEnumerable<AgentFlowRecordDto>>()
                };
            }, TimeSpan.FromDays(1));
            return resultRedis;
        }

        public AgentWalletDto Pay(AdminDto admin, decimal amount,string remark, FlowType flowType, PaymentChannelType paymentChannel,
            FlowDirectionType flowDirectionType,string orderNo)
        {
            if (admin.AgentRecord==null)
            {
                throw new ArgumentException(" 用户认证失败,错误操作 ");
            }
            AgentWalletDto agentWallet = GetWalletByAgentId(admin.AgentRecord.AgentRecordId);
            if (agentWallet == null)
            {
                throw new ArgumentException("用户钱包不存在");
            }
            if (agentWallet.Balance < amount)
            {
                throw new ArgumentException("钱包余额不足,请检查");
            }
            this.databaseContext.BeginTransaction();
            var entity = this.agentWalletData.UpdateBalance(agentWallet.AgentWalletId, amount);
            if (entity.Balance < 0)
            {
                throw new ArgumentException("钱包余额不足,请检查");
            }
            //增加余额充值流水
            AgentFlowRecordEntity agentFlowRecordEntity = new AgentFlowRecordEntity
            {
                Amount = amount,
                OrderNo = orderNo,
                CreateTime = DateTime.Now,
                Remark = $"{remark}{amount}元",
                FlowDirection = flowDirectionType.ToString(),
                FlowType = flowType.ToString(),
                FlowTypeName=flowType.GetDescriptionString(),
                Channel = paymentChannel.ToString(),
                AgentRecordId = admin.AgentRecord.AgentRecordId,
                AgentName = admin.Company.CompanyName,
                RiskLevel= Compare.GetRiskLevel(amount).ToString(),
                Balance=entity.Balance,
            };
            agentFlowRecordData.InsertAsync(agentFlowRecordEntity).GetAwaiter().GetResult();
            //TODO 添加系统流水记录
            //this.systemFinanceFlowRecordService.WriteSystemFinanceFlowRecord(current.UserId, rechargeAmount, rechargeNo, SystemFinanceFlowDirectionType.Income, FlowType.Recharge, channelType);

            this.databaseContext.Commit();
            this.redisService.DeleteMultipleKey(key, false);
            return entity.As<AgentWalletDto>();
        }

    }
}
